import type { Directive, DirectiveBinding } from 'vue'
import { useId } from 'vue'

interface Cache {
  ob: IntersectionObserver
  dataId: string
}
const cache: Array<Cache> = []

// 定义一个懒加载指令
const lazyload: Directive = {
  // 指令被绑定到元素上时调用
  mounted(el: HTMLImageElement, binding: DirectiveBinding) {
    // 创建一个IntersectionObserver实例，用于监听元素是否进入视口
    const ob = new IntersectionObserver((entries) => {
      // 获取被监听的元素
      const image = entries[0]
      // 获取元素的位置
      const { y } = image.boundingClientRect
      // 获取视口的高度
      const rootHeight = image.rootBounds?.height as number
      // 如果元素的位置小于视口的高度，说明元素已经进入视口
      if (y < rootHeight) {
        // 设置元素的src属性为指令的值
        el.src = binding.value
        // 停止监听元素
        ob.unobserve(el)
        // 如果缓存中有元素，则从缓存中移除
        if (cache.length > 0) {
          const index = cache.findIndex(
            (item) => item.dataId === el.getAttribute('data-id')
          )
          cache.splice(index, 1)
        }
      }
    })

    // 生成一个唯一的id
    const dataId = useId()
    // 将id设置到元素的data-id属性上
    el.setAttribute('data-id', dataId)
    // 将观察者和id添加到缓存中
    cache.push({
      ob,
      dataId
    })
    // 开始监听元素
    ob.observe(el)
  },
  // 指令与元素解绑时调用
  beforeUnmount(el: HTMLImageElement) {
    // 如果缓存中有元素，则从缓存中移除
    if (cache.length > 0) {
      const index = cache.findIndex(
        (item) => item.dataId === el.getAttribute('data-id')
      )
      // 停止监听元素
      cache[index].ob.unobserve(el)
      // 断开观察者
      cache[index].ob.disconnect()
      // 从缓存中移除
      cache.splice(index, 1)
    }
  }
}

// 导出懒加载指令
export default lazyload
